/*
 * @Author: 杨湲 yy7072@qq.com
 * @Date: 2025-06-27 10:17:28
 * @LastEditors: 杨湲 yy7072@qq.com
 * @LastEditTime: 2025-06-29 09:00:04
 * @FilePath: \练习1java\Calculator.java
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import javax.swing.JFrame;//窗口
import javax.swing.JPanel ;//面板
import javax.swing.JTextField;//文本框
import javax.swing.JButton;//按钮
import java.awt.event.ActionEvent;//事件处理
import java.awt.event.ActionListener;//布局
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;//尺寸
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Font;//字体
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.text.SimpleDateFormat;//日期
import java.util.Date;
import java.awt.Color;

// 继承 JFrame 为了直接复用swing框架中窗口管理的能力
// 为了子类可以直接调用 JFrame public 的方法

// ActionListener 是java中事件处理机制的核心部分
// 为了建立计算器组件和用户操作之间的响应机制
public class Calculator extends JFrame implements ActionListener{
     // 声明界面组件
  // 上下两个容器面板 文本框区域 按钮区域
    private JPanel north,center;
    // 文本框 显示计算过程、结果或者日期时间
    private JTextField field;
    // 按钮
    private JButton[] btns;
    // 初始化窗口 - 构造器 构造方法 无参构造器
    public Calculator(){
         // 设置窗口title
        setTitle("绿色计算器");
         // 设置窗口大小
        setSize(700,700);
        // 设置窗口关闭时程序
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        // 设置窗口居中显示
        setLocationRelativeTo(null);
        // 初始化界面组件
        initComponent();
        // 设置窗口显示
        setVisible(true);

    }
     // 初始化界面组件
    private void initComponent(){
        // System.out.println("initComponent");
    // 创建面板容器
    // 容器面板 文本框区域
        //System.out.println("initComponent");
        north = new JPanel();
        // 容器面板 按钮区域
        center = new JPanel();
         // 文本框 显示计算过程、结果或者日期时间
         // 设置输入框大小 首选尺寸
         north.setBackground(new Color(46,204,113));//上方面板
         center.setBackground(new Color(39,174,96));//中间的面板
         field = new JTextField();
         field.setPreferredSize(new Dimension(700,150));
        // 禁用文字输入 禁止通过电脑键盘输入编辑
         field.setEditable(false);
         // 设置输入框中文字大小
         field.setFont(new Font("SansSerif",Font.BOLD,35));
         field.setBackground(new Color(227,241,230));//文本框面板
         field.setForeground(Color.WHITE);
         // 按钮文本内容
        String[] str =new String[]{
            "7","8","9","+",
            "4","5","6","-",
            "1","2","3","×",
            "0",".","=","÷",
            "C","B","T","S"

        }; // 按钮数组
        btns = new JButton[str.length];
        //初始化按钮绿色背景，白色文字
        for(int i = 0;i<btns.length;i++){
            btns[i] = new JButton(str[i]);//创建按钮，文本取自str[i]
            btns[i].setFont(new Font("Microsoft YaHei",Font.BOLD,25));//字体：微软雅黑，加粗，25号
            btns[i].setBackground(new Color(127,219,20));//亮绿按钮
            btns[i].setForeground(Color.WHITE);//白色文字
            btns[i].setFocusPainted(false);//取消按钮聚焦边框，美观优化
        }
        // 将组件放到窗口中
    // 设置布局管理器
    // north 顶部面板 使用 BorderLayout 边界布局
        north.setLayout(new BorderLayout(700,150));
        // center 中间面板 使用5行4列 的 网格布局
        center.setLayout(new GridLayout(5,4));
         // 组件设置
    // field 文本框 添加到 north 顶部面板 使用 BorderLayout 居中
        north.add(field,BorderLayout.CENTER);
         // btns 按钮 添加到 center 面板 增强for循环
        for(JButton btn : btns){
            // 通过遍历将所有按钮添加到 center 面板
        center.add(btn);

        }
        // 将 north 顶部面板 添加到窗口中
        add(north,BorderLayout.NORTH);
         // 将 center 面板 添加到窗口中
        add(center);
        // 绑定按钮的监听事件
        for(JButton btn : btns){
            btn.addActionListener(this);
          
        }
        }
      
       
    // 处理按键文本
    private void setBtnText(String text){
       // System.out.println("text length:" + text.length());
       // System.out.println("field text length:" +field.getText().length());

        switch (text){
            case "C":
            //清空功能
            field.setText("");
           // System.out.println("C");
            break;
            case "B":
            //System.out.println("B");
            //退格功能
            //获取输入框的内容
            String numText= field.getText();
            //两种情况is Empty()
            if(numText.length()!=0){
                //输入框的内容不为空
                //System.out.println("输入框的内容不为空:"+numText);
                //numText的长度减1
                String lastText = numText.substring(0,numText.length()-1);
                //System.out.println("lastText"+lastText);
                //将截取后的文本设置道输入框
                field.setText(lastText);
            }else{
                //System.out.println("输入框的内容为空");

            }
            //System.out.println("B");
            break;
            case "T":
            //显示当前时间:格式为年月日 时分秒
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            field.setText(sdf.format(new Date()));
            //System.out.println("T:显示时间");
            break;
            case"S":
            //播放音乐
            break;
            //System.out.println("S:自定义功能");
            case"=":
            calculate();
           // System.out.println("=");
            
            break;
            case".":
            //处理小数点前导零逻辑
            String currentText = field.getText();
           if(currentText.isEmpty()||currentText.matches(".*[+-×÷]$")){
            field.setText(currentText + "0.");
           }else{
            if(! currentText.contains(".")){
                field.setText(currentText +".");
            }
           }
            
            break;
            default:
             // 按下数字键或者运算符 要把文字放到输入框中
        // 如果之前输入框中有文字 做拼接
            String oldText = field.getText();
            field.setText(oldText + text);
            break;
        


        } // 实现 ActionListener 接口中的抽象方法 处理事件
       
    }
    private void calculate(){
    String expression = field.getText();
    // 校验输入格式
    if (expression.isEmpty() ||expression.matches(".*[+\\-*/×÷]$")){
        field.setText("输入格式错误");
        return;
    }
            //用户输入1+1，
            //我们执行计算操作，然后将结果展示道文本框
            //如果表达式中有×÷要替换为*/

         expression = expression.replace("×","*").replace("÷","/");
         System.out.println("计算表达式:"+expression);
            //我们执行计算操作,使用js计算引擎
            ScriptEngineManager manager = new ScriptEngineManager();
            //初始化计算引擎，使用javascript解析数学表达式
            ScriptEngine engine = manager.getEngineByName("javascript");
            try{
                //计算过程可能出现异常这里需要处理异常
                //try中放的是可能出现异常的代码
            //开始计算
            Object result = engine.eval(expression);
            // 然后将结果展示到文本框
            field.setText(result.toString());
            }catch(ScriptException e){
                 // catch 中放的是异常的处理方式
                field.setText("运算错误");
                e.printStackTrace();
            }
        

    }
    @Override
    public void actionPerformed(ActionEvent a){
        // 此处可以捕获到 ActionListener 监听的事件
    // System.out.println(a.getSource());
    // 获取被点击的按钮 或者按钮的文字
        Object source = a.getSource();
        if(source instanceof JButton){
            JButton btn = (JButton) source;
            String text = btn.getText();
             // System.out.println(text);
      // 处理对应按键文字
           setBtnText(text);
        }

    }
    public static void main(String[] args){
       // System.out.println("hello,Calculator");
    // 创建类的对象 - 线程不安全
    // new Calculator();
    // 是 Java Swing 开发中确保线程安全的核心代码
    // EDT 线程保障
    // Swing 要求所有 GUI 操作（组件创建、属性修改、事件处理）必须在 Event Dispatch Thread (EDT) 执行。这里代码通过
    // invokeLater 将 Calculator 类的实例化操作（即 GUI 初始化）提交到 EDT 队列，确保线程安全。
    // 异步执行机制
    // invokeLater 会将传入的 Runnable 任务（此处为 Calculator::new 方法引用）放入 EDT 的任务队列，由 EDT
    // 按顺序执行。这避免了直接操作 GUI 导致的线程竞争问题。
       SwingUtilities.invokeLater(Calculator::new);
    }
}
